home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / doc / other / equeltut.q < prev    next >
Encoding:
Text File  |  1992-11-19  |  14.3 KB  |  611 lines

  1. #
  2. /*
  3. ** This    is intended as a tutorial example of  an  Equel     program.
  4. ** You    should    be  familiar  with  both  C and    Quel before going
  5. ** through the examples.  The program may be run to see     how  the
  6. ** examples  actually  work.  To compile and run this program you
  7. ** should run the following shell commands:
  8. **
  9. **        equel equeltut.q
  10. **        cc equeltut.c -lq
  11. **        a.out
  12. **
  13. ** The first command invokes the Equel    pre-processor  which  in-
  14. ** serts  code    to send    queries    to INGRES.  The    output is left in
  15. ** the file "equeltut.c" in  this  case.   In  general,    the  pre-
  16. ** processor is    invoked    as:
  17. **
  18. **        equel [-d] [-f]    [-r] file1.q [file2.q ...]
  19. **
  20. ** The output is left in "file1.c", etc.  The -d flag tells Equel
  21. ** to  leave line number information in    the file so that run time
  22. ** errors can be associated with the proper query.
  23. **
  24. ** It is possible to use the C-preprocessor to include files with
  25. ** Equel statements and/or declarations    in it if these files have
  26. ** names ending    in ".q.h". Such    files will be processed    by equel,
  27. ** and    a C version left in the    file ending in ".c.h", which will
  28. ** be #included    by the C pre-processor.    Files which are    #included
  29. ** but whose names do not end in ".q.h"    will be    ignored    by Equel.
  30. */
  31.  
  32.  
  33. /*
  34. ** Equel uses the same syntax as Quel in almost    all cases.  There
  35. ** are    a  few    differences  between Equel and Quel and    also some
  36. ** subtleties in interfaceing Quel and C constructs.  Some impor-
  37. ** tant    points are:
  38. **
  39. **    C-variables declared  to  Equel     are  used  as    variables
  40. ** throughout Equel statements,    except inside  strings or when preceded
  41. ** by the non-referencing operator '#'.     In particular,    be  care-
  42. ** ful with variable names which are the same as domain    names.
  43. **
  44. **    All strings passed to C-variables  from     INGRES     will  be
  45. ** null     terminated.   This  will  make    them one byte longer than
  46. ** they    were in    the relation, so you must declare character arrays
  47. ** to be one byte longer than the domain from which the data will
  48. ** come.
  49. **
  50. **    Retrieve statements with no result relation have  a  dif-
  51. ** ferent  interpretation  in  Equel than in Quel.  There will be
  52. ** many    examples of this.
  53. */
  54.  
  55.  
  56.  
  57.  
  58.  
  59. /*
  60. ** First some of the queries found in "A Tutorial on INGRES"  are
  61. ** mapped  into     Equel    so  that the similarities and differences
  62. ** between the two modes of accessing INGRES can be seen.
  63. */
  64.  
  65.  
  66.  
  67.  
  68. /*
  69. ** We start by declaring some variables    that will be  needed  for
  70. ** the interaction.  Note that the variables are global    to Equel,
  71. ** that    is the declarations are    in effect for the entire file.
  72. */
  73.  
  74. ## char    pname[21];    /*
  75.             ** Pname is dimensioned    to hold    one  more
  76.             ** character  than the pname field of the
  77.             ** parts relation.  We will need the  ex-
  78.             ** tra    character so that Equel    will have
  79.             ** enough space     to  null  terminate  the
  80.             ** string.   More on this later.  
  81.             **    We must use the non-referencing 
  82.             ** operator  when using  "pname" as a 
  83.             ** field name, as the field has the same 
  84.             ** name as  tha  variable and equel will 
  85.             ** assume we mean the variable if we just 
  86.             ** write "pname."
  87.             */
  88.  
  89. ## char    col[9];        /*
  90.             ** This    will be    used to    hold color attri-
  91.             ** butes  from the parts relation.  It is
  92.             ** named "col" insted of "color" so  that
  93.             ** the    term "p.color" does not    contain    a
  94.             ** variable reference, and  may     be  used
  95.             ** without the non-referencing operator.
  96.             */
  97.  
  98. main(argc, argv)
  99. int    argc;
  100. char    *argv[];
  101.  
  102. {
  103.  
  104.     /*
  105.     ** We start the    interaction with INGRES    using  data  base
  106.     ** demo.
  107.     */
  108.  
  109.  
  110. ##    ingres "-i210" demo
  111.  
  112.     /*
  113.     ** Up to 9 arguments may be specified to the INGRES call.
  114.     ** Here     we  have  modified  the  integer  output format.
  115.     ** Flags must be in quotes so that the plus or minus  are
  116.     ** not parsed incorrectly.
  117.     */
  118.  
  119.  
  120.  
  121.     /*
  122.     ** As in the INGRES tutorial, we may print the parts rela-
  123.     ** tion:
  124.     */
  125.  
  126. ##    print parts
  127.  
  128.     /*
  129.     ** Note    that this identical to the Quel    statement  except
  130.     ** that    the line is tagged with    the "##" telling the Equ-
  131.     ** el pre-processor to translate this line into     standard
  132.     ** C
  133.     */
  134.  
  135.     /*
  136.     ** The next section of code is intended    to  parallel  the
  137.     ** third query    in the Tutorial    [page 4]
  138.     */
  139.  
  140. ##    range of p is parts    /*
  141.                 ** This    is identical to    the  Quel
  142.                 ** syntax.   Note also the use of
  143.                 ** a comment in    an  Equel  state-
  144.                 ** ment
  145.                 */
  146.  
  147.  
  148.     /*
  149.      ** Note that the first    pname is assumed to refer to the  vari-
  150.      ** able  "pname", while the second pname is assumed to    be a
  151.      ** constant name (as opposed to the value of  the  vari-
  152.      ** able  "pname")  because of the non-referencing opera-
  153.      ** tor.
  154.     */
  155. ##    retrieve (pname    = p.#pname)
  156. ##    {
  157.         /*
  158.         ** Everything inside the braces    is  repeated  for
  159.         ** each    tuple that is retrieved.
  160.         */
  161.  
  162.         printf("%s\n", pname);
  163.  
  164.         /*
  165.         ** pname is a properly terminated C string.  Equ-
  166.         ** el  null  terminates     ALL  strings  which  are
  167.         ** passed from INGRES.    Strings    will be    of length
  168.         ** one    more than the width of the attribute.  It
  169.         ** is assumed that the user has     provided  enough
  170.         ** room!!
  171.         */
  172. ##    }
  173.  
  174.  
  175.  
  176.     /*
  177.     ** Now we will retrieve    the colors and names of    the parts
  178.     ** We will skip    the error in the Tutorial and simply note
  179.     ** that    the  Equel  interpreter     would    catch  the  error
  180.     ** presented on    page 4:
  181.     **    ##    retrieve pname = p.#pname, col =  p.color
  182.     ** with    the message:
  183.     **    IS = '=' : line    7, syntax error    
  184.     ** which  is  almost as helpful as the Quel message.
  185.     */
  186.  
  187.  
  188.  
  189.  
  190. ##    retrieve (pname    = p.#pname, col    = p.color)
  191. ##        /*
  192.         ** The name "col" was used for the variable  name
  193.         ** insted of "color".  The latter would    be treat-
  194.         ** ed as a variable in the phrase  "p.color"  and
  195.         ** INGRES  would  see  "p." followed by    the value
  196.         ** color had at    runtime.
  197.         **
  198.         ** The comment in this situation must start on    a
  199.         ** line    with a "##" since Equel    will look for the
  200.         ** "## {" to be     contiguous  with  the    retrieve.
  201.         ** The same holds for blank lines, they must begin
  202.         ** with    a "##" if they come  before the     "##  {".
  203.         */
  204. ##    {
  205.         printf("The color of the %s is %s\n", pname,col);
  206. ##    }
  207.  
  208.     /*
  209.     ** The ##{ and ##} are needed, even if you wish to repeat
  210.     ** only one line of C-code inside the retrieve.
  211.     */
  212.  
  213.     /*
  214.     ** To retrieve and print the parts which are gray we  may
  215.     ** write:
  216.     */
  217.  
  218.     printf("The following parts are    gray:\n");
  219. ##    retrieve (pname    = p.#pname)
  220. ##    where    p.color    = "gray"
  221. ##    {
  222.         printf("\t%s\n", pname);
  223. ##    }
  224.  
  225.  
  226.     /*
  227.     ** The above query is similar to the query on page  5  of
  228.     ** the Tutorial.
  229.     */
  230.  
  231.  
  232.     /*
  233.     ** In Equel there is no    notion of a "query buffer" as  in
  234.     ** the    INGRES    Terminal  Monitor.   If    we want    to do the
  235.     ** query on page 6 of the  Tutorial  we     must  completely
  236.     ** specify the query (except for the range statements):
  237.     */
  238.  
  239. ##    retrieve (pname    = p.#pname, col    = p.color)
  240. ##    where    p.color    = "gray"
  241. ##    or    p.color    = "pink"
  242. ##    {
  243.         printf("The color of the %s is %s\n", pname, col);
  244. ##    }
  245.  
  246.  
  247.  
  248.     /*
  249.     ** We will now leave the Tutorial behind and use some  of
  250.     ** features particular to Equel.
  251.     */
  252.  
  253.  
  254.     example1();
  255.  
  256.     /*
  257.     ** Next    we have    an interactive example...
  258.     */
  259.  
  260.     raise();
  261.  
  262.     /*
  263.     ** Next an example of "parametrized" Equel statements
  264.     */
  265.  
  266.     param_ex();
  267. }
  268.  
  269.  
  270. /*
  271. ** Suppose we want to bring parts of a    relation  into    core  for
  272. ** some    number crunching which would be    difficult in INGRES.
  273. **
  274. ** This    example    brings elements    of the supply  relation     into  an
  275. ** array of structures.
  276. */
  277. # define    MAXDATA        20
  278.  
  279.  
  280.  
  281.  
  282. /*
  283. ** This defines the fields "pnum", "snum", and    "quan" to Equel.
  284. */
  285. ## struct supply
  286. ## {
  287. ##    int pnum, snum;
  288. ##    int quan;
  289. ## };
  290.  
  291. /*
  292. ** The    ##{ and    ##} at the start and end of the    example1()  func-
  293. ** tion  indicate  the     scope of variables declared within them.
  294. ** Therefore data is    considered by Equel to be local    to  exam-
  295. ** ple1.  Any    free  block (a ##{...##} not immeadiately after    a
  296. ** ##retrieve without a result    relation [an  into])  makes  vari-
  297. ** ables declared within it     be local (there    is, however, only
  298. ** one    level of locality; i.e.    either a variable  is  global  to
  299. ** the     file,    or  it    is  local to the outermost enclosing free
  300. ** block.
  301. */
  302.  
  303. example1()
  304. ## {
  305.  
  306. ##    struct    supply    data [MAXDATA +    1];
  307.     register int    i;
  308.  
  309.     i = 0;
  310.  
  311. ##    range of s is supply
  312.  
  313.     /*
  314.     ** The structure field names are known    to  be    structure
  315.     ** fields  beacuse they    were declared as such, and follow
  316.     ** the structure variable "data".  On    the right side of
  317.     ** the    equals    sign  (=) they are not in the position of
  318.     ** structure fields so are assumed to  be  domain  names,
  319.     ** although  the  non-referencing  operator could be used
  320.     ** here    any way    for clarity.
  321.     */
  322.  
  323. ##    retrieve (data [i].pnum = s.pnum,
  324. ##        data [i].snum    = s.snum,
  325. ##        data [i].quan    = s.quan)
  326. ##    where s.shipdate <= "76-12-10"
  327. ##    {
  328.         printf("supplier #%d, supplies %d of part %d.\n",
  329.         data [i].snum, data [i].quan, data [i].pnum);
  330.         if (i++    >= MAXDATA - 1)
  331.         {
  332.             printf("Too much data!\n");
  333.             break;
  334.             /*
  335.             ** The break is     legal    because     the  re-
  336.             ** trieve  is  converted  into    a "while"
  337.             ** statement.  Break is    the only  accept-
  338.             ** able     way to    get out    of a retrieve due
  339.             ** to an user detected error.    There  is
  340.             ** code     after    the  "while" to    flush out
  341.             ** the data sent by INGRES which was  not
  342.             ** used    by the Equel process.
  343.             */
  344.         }
  345.  
  346. ##    }
  347. ## }
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355. /*
  356. ** The routine provides    an  interactive     secession  for     updating
  357. ** salaries.  There are    other ways of accomplishing this interac-
  358. ** tion    but this mode brings out some of the possible pitfalls.
  359. */
  360.  
  361. raise()
  362. ## {
  363.     int        flag;
  364.     int        per;
  365. ##    char        percent[10];
  366. ##    char        rname[21];
  367. ##    char        ename[21];
  368. ##    int        sal;
  369. ##    char        domain[20];
  370. ##    char        info[255];
  371.     extern        *IIinterrupt, reset();
  372.  
  373. ##    range of e is employee
  374.  
  375.     /*
  376.     ** Since the range statement will be in    effect as long as
  377.     ** INGRES  is  running    we   declare it    at the top of the
  378.     ** loop    rather than each time through the loop.
  379.     */
  380.  
  381.  
  382.  
  383.     /*
  384.     ** Before entering the loop we arrange to  continue  pro-
  385.     ** cessing  after  an interrupt    from the user.    It is im-
  386.     ** perative that we do not catch the signal at this point
  387.     ** since  INGRES  will    catch  the signal and try to syn-
  388.     ** chronize with the Equel process.  When the Equel  pro-
  389.     ** cess     has  been  synchronized  it will call (*IIinter-
  390.     ** rupt)().
  391.     */
  392.  
  393. #if 0
  394.     IIinterrupt = reset;
  395.     setexit();
  396. #endif
  397. loop:
  398.     printf("Please enter employee's    name\n");
  399.  
  400.     if (eread(ename))
  401.         return (0);
  402.  
  403.     if (ename[0] ==    '?' && ename[1]    == '\0')
  404. ##        print employee
  405.     else
  406.     {
  407.         flag = 0;
  408.  
  409.         /*
  410.         ** In this interaction we do  three  queries  and
  411.         ** let INGRES do the arithmetic.  The name is re-
  412.         ** trieved into    rname  since  ename  may  contain
  413.         ** pattern  matching characters    and more than one
  414.         ** name    may be retrieved.   For     example  "Ross*"
  415.         ** may    be  entered  and  both Stanley and Stuart
  416.         ** will    get raises.
  417.         */
  418.  
  419. ##        retrieve (rname    = e.name, sal =    e.salary)
  420. ##            where e.name = ename
  421. ##        {
  422.             printf("The current salary of %s is %d\n",
  423.                 rname, sal);
  424.             flag = 1;
  425. ##        }
  426.  
  427.         if (!flag)
  428.         {
  429.             printf("No such    employee\n");
  430.             goto loop;
  431.         }
  432.         printf("Enter percent increase=");
  433.         if (eread(percent))
  434.             goto loop;
  435.  
  436.  
  437.         /*
  438.         ** There is no    facility  in  Equel  to     examine,
  439.         ** modify and then put back a tuple.  The replace
  440.         ** must    contain    the qualification since    there  is
  441.         ** no  connection  between  the    previous retrieve
  442.         ** and the replace.
  443.         */
  444. ##        replace    e (salary = e.salary + float8(percent)/100.    * e.salary)
  445. ##            where e.name = ename
  446.  
  447.  
  448.         per = atoi(percent);
  449.  
  450. ##        retrieve (rname    = e.name, sal =    e.salary)
  451. ##            where e.name = ename
  452. ##        {
  453.             printf("With that ");
  454.             if (per    < 5)
  455.                 printf("piddly");
  456.             else if    (per < 10)
  457.                 printf("modest");
  458.             else if    (per < 30)
  459.                 printf("inflation fighting");
  460.             else
  461.                 printf("tremendous");
  462.             printf(" raise,    %s now makes $%d\n",rname,sal);
  463. ##        }
  464.  
  465.  
  466.         printf("Do you want any    other information about    %s?\n"
  467.             , ename);
  468.  
  469.         if (eread(domain) || domain[0] == 'n' )
  470.             goto loop;
  471.  
  472.         printf("Enter domain:  ");
  473.  
  474.         if (eread(domain))
  475.             goto loop;
  476.  
  477.         /*
  478.         ** If the user responds    with a '?' then    show  him
  479.         ** all    possible  domains by printing out the at-
  480.         ** tributes of that relation from  the    tuple  in
  481.         ** the "attribute" relation.
  482.         */
  483.  
  484.         if (domain[0] == '?' &&    domain[1] == '\0')
  485.         {
  486.  
  487. ##            range of a is attribute
  488.  
  489. ##            retrieve(domain    = a.attname)
  490. ##                where a.attrelid = "employee"
  491. ##            {
  492.                 printf("\t%s\n", domain);
  493. ##            }
  494.             printf("Enter domain:  ");
  495.  
  496.             if (eread(domain))
  497.                 goto loop;
  498.         }
  499.  
  500.  
  501.         /*
  502.         ** Here    we use a C-variable  as     a  domain  name.
  503.         ** The    value of the variable is passed    to INGRES
  504.         ** and interpreted as part of the query.
  505.         */
  506.  
  507.  
  508.  
  509.         /*
  510.         ** The ascii funciton is used because the type of
  511.         ** the    domain    is not known.  Ascii applied to    a
  512.         ** character domain does nothing.
  513.         */
  514. ##        retrieve (rname    = e.name, info = ascii(e.domain))
  515. ##            where e.name = ename
  516. ##        {
  517.  
  518.             printf("%s\t%s = %s\n",    rname, domain, info);
  519. ##        }
  520.  
  521.     }
  522.     goto loop;
  523. }
  524.  
  525. /*
  526. ** This    routine    shows the use of parametrized  equel  statements.
  527. ** These  are  equel statements    where the target list is undeter-
  528. ** mined until    run-time.  In  this  way  a  variable  number  of
  529. ** domains,  or     variable  types  may  be  used    in the same Equel
  530. ** statements.
  531. */
  532.  
  533. param_ex()
  534. {
  535.     char        name [25];    /*
  536.                      ** Variables used in the
  537.                      ** target   list   of    a
  538.                      ** parametrized   state-
  539.                      ** ment  need not be de-
  540.                      ** clared to equel.
  541.                     */
  542.     register char    *string;
  543.     int        empno;
  544.     char        *tl_vector [100];
  545.  
  546.     /*
  547.     ** Another way to do
  548.     **  ##    retrieve (name = e.#name, empno    =e.number) 
  549.     **  ##    {
  550.     **        printf("employee #%d  is  called  %s.\n",
  551.     **         empno, name);
  552.     **  ##    }
  553.     */
  554.  
  555.     /*
  556.     ** This    statement initializes the target  list    variable.
  557.     ** The '%' sequences indicate the type of the correspond-
  558.     ** ing argument    following.  Valid types    are :
  559.     **    %c -- string of    any length
  560.     **    %i2, %i4 -- integer or long
  561.     **    %f4, %f8 -- float or double
  562.     */
  563.  
  564.     string = "%c is    e.name,    %i2 = e.number";
  565.     tl_vector [0] = name;
  566.     tl_vector [1] = &empno;
  567.  
  568. ##    param retrieve (string, tl_vector)
  569. ##    /*
  570.     ** This    statement could    also be    written    
  571.     ** ## param retrieve ("%c is e.name, %i2 = e.number", 
  572.     ** ##    tl_vector)
  573.     */
  574. ##    {
  575.         printf("employee #%d is    called %s.\n", empno, name);
  576. ##    }
  577.  
  578.     /*
  579.     ** Parametrized  append,  copy,  create, define view,
  580.     ** retrieve with a result relation, and replace, may 
  581.     ** also be used.
  582.     **
  583.     ** One could  say  :  
  584.     ** ##  param append to employee ("name is %c, number is %i2",
  585.     ** ##      tl_vector)
  586.     */
  587. ##}
  588.  
  589.  
  590.  
  591. /*
  592. ** This    routine    reads a    string from the    terminal  and  null  ter-
  593. ** minates it.    It returns 1 when an eof is read.
  594. */
  595.  
  596. eread(p)
  597. char    *p;
  598. {
  599.     char    c;
  600.     while(c    = getchar())
  601.     {
  602.         if(c ==    '\n')
  603.         {
  604.             *p = 0;
  605.             return(0);
  606.         }
  607.         *p++ = c;
  608.     }
  609.     return(1);
  610. }
  611.